import os

import allure
import yaml

from utils.logging_tool.recordlog import logs
from utils.mysql_tool.connect_mysql import ConnectMysql


class ReadYamlDATA:

    @classmethod
    def get_yaml_files(self, directory):
        """
        获取指定目录下以及子目录下的所有文件
        :param directory: 指定目录
        :return:
        """
        # 将所有的yaml文件路径添加到列表中
        yaml_files_path = []
        # os.walk(directory)函数用于遍历指定目录下的所有文件和子目录
        for root, dirs, files in os.walk(directory):
            for file in files:
                if file.endswith('.yaml') or file.endswith('.yml'):
                    # os.path.join(root,file）返回文件的完整路径。
                    file_path = os.path.join(root, file).replace("\\", '/')
                    yaml_files_path.append(file_path)
        return yaml_files_path

    def get_testcase_yaml(self, file):
        """
        获取yaml测试文件，并进行处理
        :param file: 指定文件
        :return:
        """
        # 处理用例等级转成严重等级 blocker、critical、normal、minor、trivial
        rank_mapping = {'P1': 'blocker',
                        'P2': 'critical',
                        'P3': 'normal',
                        'P4': 'minor',
                        'P5': 'trivial'}
        key_list = list(rank_mapping.keys())
        testcase_list = []
        try:
            with open(file, 'r', encoding='utf-8') as f:
                data = yaml.safe_load(f)
                # 判断 baseInfo 数量
                if len(data) <= 1:  # 键值对小于 1 只有一个baseInfo，需要将testCase部分与baseInfo整合一起作为一个用例
                    yam_data = data[0]
                    base_info = yam_data.get('baseInfo')

                    # 模块名称
                    feature = base_info.get('feature', None)
                    if feature is None:
                        base_info['feature'] = '未定义模块名称'

                    # 子模块名称
                    story = base_info.get('story', None)
                    if story is None:
                        base_info['story'] = '未定义子模块名称'

                    for testcase in yam_data.get('testCase'):
                        # 用例名称
                        case_name = testcase.get('case_name', None)
                        if case_name is None:
                            testcase['case_name'] = '未定义用例名称'

                        # 用例等级
                        rank = testcase.get('rank', 'P3')  # rank 字段不存在 默认 P3 对应严重程度一般
                        if rank in key_list:
                            testcase['rank'] = rank_mapping.get(rank)
                        else:
                            testcase['rank'] = 'normal'  # 不填或者除了P1-P5都默认为P3

                        param = [base_info, testcase]
                        testcase_list.append(param)

                    return testcase_list
                else:
                    # 列表数据  包含多个baseInfo，一个baseInfo 对应一个 testCase
                    for yam_data in data:
                        base_info = yam_data.get('baseInfo')

                        # 模块名称
                        feature = base_info.get('feature', None)
                        if feature is None:
                            base_info['feature'] = '未定义模块名称'

                        # 子模块名称
                        story = base_info.get('story', None)
                        if story is None:
                            base_info['story'] = '未定义子模块名称'

                        testcase = yam_data.get('testCase')
                        for ts in testcase:
                            # 用例名称
                            case_name = ts.get('case_name', None)
                            if case_name is None:
                                ts['case_name'] = '未定义用例名称'

                            # 用例等级
                            rank = ts.get('rank', 'P3')
                            if rank in key_list:
                                ts['rank'] = rank_mapping.get(rank)
                            else:
                                ts['rank'] = 'normal'

                        testcase_list.append(yam_data)
                    return testcase_list

        except UnicodeDecodeError:
            logs.error(f"【{file}】文件编码格式错误，--尝试使用utf-8编码解码YAML文件时发生了错误，请确保你的yaml文件是UTF-8格式！")
        except FileNotFoundError:
            logs.error(f'【{file}】文件未找到，请检查路径是否正确')
        except Exception as e:
            logs.error(f'获取【{file}】文件数据时出现未知错误: {str(e)}')

    def get_smokecase_yaml(self, file):
        """
        获取yaml冒烟测试文件，并进行处理，冒烟用例级别为P1\P2
        :param file: 指定文件
        :return:
        """
        # 处理用例等级转成严重等级 blocker、critical、normal、minor、trivial
        rank_mapping = {'P1': 'blocker',
                        'P2': 'critical'}
        key_list = list(rank_mapping.keys())
        testcase_list = []
        try:
            with open(file, 'r', encoding='utf-8') as f:
                data = yaml.safe_load(f)
                # 判断 baseInfo 数量
                if len(data) <= 1:  # 键值对小于 1 只有一个baseInfo，需要将testCase部分与baseInfo整合一起作为一个用例
                    yam_data = data[0]
                    base_info = yam_data.get('baseInfo')

                    # 模块名称
                    feature = base_info.get('feature', None)
                    if feature is None:
                        base_info['feature'] = '未定义模块名称'

                    # 子模块名称
                    story = base_info.get('story', None)
                    if story is None:
                        base_info['story'] = '未定义子模块名称'

                    for testcase in yam_data.get('testCase'):
                        # 用例名称
                        case_name = testcase.get('case_name', None)
                        if case_name is None:
                            testcase['case_name'] = '未定义用例名称'

                        # 用例等级
                        rank = testcase.get('rank', 'P3')  # rank 字段不存在 默认 P3 对应严重程度一般
                        if rank in key_list:
                            testcase['rank'] = rank_mapping.get(rank)
                            param = [base_info, testcase]
                            testcase_list.append(param)
                        else:
                            testcase['rank'] = 'normal'  # 不填或者除了P1-P5都默认为P3,不做处理
                    return testcase_list
                else:
                    # 列表数据  包含多个baseInfo，一个baseInfo 对应一个 testCase
                    for yam_data in data:
                        base_info = yam_data.get('baseInfo')

                        # 模块名称
                        feature = base_info.get('feature', None)
                        if feature is None:
                            base_info['feature'] = '未定义模块名称'

                        # 子模块名称
                        story = base_info.get('story', None)
                        if story is None:
                            base_info['story'] = '未定义子模块名称'

                        testcase = yam_data.get('testCase')
                        for ts in testcase:
                            # 用例名称
                            case_name = ts.get('case_name', None)
                            if case_name is None:
                                ts['case_name'] = '未定义用例名称'

                            # 用例等级
                            rank = ts.get('rank', 'P3')
                            if rank in key_list:
                                ts['rank'] = rank_mapping.get(rank)
                                testcase_list.append(yam_data)
                            else:
                                ts['rank'] = 'normal'
                    return testcase_list

        except UnicodeDecodeError:
            logs.error(f"【{file}】文件编码格式错误，--尝试使用utf-8编码解码YAML文件时发生了错误，请确保你的yaml文件是UTF-8格式！")
        except FileNotFoundError:
            logs.error(f'【{file}】文件未找到，请检查路径是否正确')
        except Exception as e:
            logs.error(f'获取【{file}】文件数据时出现未知错误: {str(e)}')

    def get_testcase_yaml_all(self, directory):
        """
        对指定目录下所有的yaml文件内测试用例进行合并（列表合并）
        :param directory: 指定目录
        :return:
        """
        testcases = []
        files = self.get_yaml_files(directory)
        for file in files:
            testcase = self.get_testcase_yaml(file)
            testcases.extend(testcase)
        return testcases

    def get_smokecase_yaml_all(self, directory):
        """
        对指定目录下所有的yaml文件内冒烟测试用例进行合并（列表合并）
        :param directory: 指定目录
        :return:
        """
        testcases = []
        files = self.get_yaml_files(directory)
        for file in files:
            testcase = self.get_smokecase_yaml(file)
            testcases.extend(testcase)
        return testcases

    @allure.step("测试用例前置")
    def testcase_setup(self, testcases, index):
        """
        测试用例前置操作
        :param testcases:获取到的所有用例
        :param index:
        :return:
        """
        # 从yaml 文件中获取前置方式
        if len(testcases) <= index:
            return
        i = 0
        for i in range(index, index + 1):
            testcase = testcases[i]
            casename = testcase[1].get('case_name')
            logs.info(f'【用例标题】{casename}')
            logs.info(f'【用例信息】{testcase}')
            try:
                if 'setup' in testcase[1]:  # 前置操作
                    # 获取前置方式
                    type = testcase[1]['setup'].get('type', None)
                    if type == 'db':  # 数据库操作
                        database = testcase[1]['setup'].get('database', None)
                        sqls = testcase[1]['setup'].get('sqls', None)
                        if sqls is None:
                            logs.info(f'sql语句为空，未进行前置操作')
                        else:  # sql语句不为空
                            ConnectMysql(database).execute_sqls(sqls)
                            allure.attach(database, f"数据库名：{database}", allure.attachment_type.TEXT)
                            allure.attach(sqls, "sql语句", allure.attachment_type.TEXT)
                    elif type == 'api':  # 调用接口
                        logs.info('暂不支持api的配置方式，敬请期待~~')
                    elif type is None:
                        logs.info('前置方式为空,未进行前置操作')
                    else:
                        logs.error(f'不支持的前置方式:{type}，未进行前置操作')
                else:
                    logs.info('不需要前置操作')
            except Exception as e:
                logs.error(f'前置操作失败！err={e}')

    @allure.step("测试用例后置")
    def testcase_teardown(self, testcases, index):
        """
        测试用例后置操作
        :param type：填写 db 和 qpi
        :param testcases: 获取到的所有用例
        :param sqls: sql语句，支持多条
        :return:
        """
        # 从yaml 文件中获取后置方式
        if len(testcases) <= index:
            return
        i = 0
        for i in range(index, index + 1):
            testcase = testcases[i]
            try:
                if 'teardown' in testcase[1]:
                    type = testcase[1]['teardown'].get('type', None)
                    if type == 'db':  # 数据库操作
                        database = testcase[1]['teardown'].get('database', None)
                        sqls = testcase[1]['teardown'].get('sqls', None)
                        if sqls is not None:  # sql语句不为空
                            ConnectMysql(database).execute_sqls(sqls)
                            allure.attach(database, f"数据库名：{database}", allure.attachment_type.TEXT)
                            allure.attach(sqls, "sql语句", allure.attachment_type.TEXT)
                    elif type == 'api':  # 调用接口
                        logs.info('暂不支持api的配置方式，敬请期待~~')
                    elif type is None:
                        logs.error('后置方式为空,后置操作失败！')
                    else:
                        logs.error(f'不支持的后置方式:{type}，后置操作失败！')
                else:
                    logs.info('不需要后置操作')
            except Exception as e:
                logs.error(f'后置操作失败！err={e}')


if __name__ == '__main__':
    file_path = '../../data/yaml'
    yaml_reader = ReadYamlDATA()
    data = yaml_reader.get_testcase_yaml_all(file_path)
    print(data[0])
